package com.bawei.hostapp.plugincore;

import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.Resources;

import com.bawei.hostapp.App;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

import dalvik.system.DexClassLoader;

/**
 * @Author : yaotianxue
 * @Time : On 2023/6/5 17:29
 * @Description : PluginManager
 */
public class PluginManager {
    private Context mContext;
    private PluginManager(Context context){
        this.mContext = context;
    }
    private static volatile PluginManager mPluginManager ;
    public static PluginManager getInstance(Context context){
        if(mPluginManager == null){
            synchronized (PluginManager.class){
                if(mPluginManager == null){
                    mPluginManager = new PluginManager(context);
                }
            }
        }
        return mPluginManager;
    }

    public PluginManager init() throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {

        loadApk();
        HookUtils.hookAmS(mContext);
        HookUtils.hookHandler(mContext);
        return this;
    }


    private void loadApk() throws NoSuchFieldException, IllegalAccessException {
        //0。插件apk位置以及缓存位置
        String pluginStr = mContext.getExternalFilesDir(null).getAbsolutePath()+"/pluginapp-debug.apk";
        String cache_plugin = mContext.getDir("cache_plugin", Context.MODE_PRIVATE).getAbsolutePath();
        //1：通过DexClassLoader获得插件apk中dexElements
        DexClassLoader dexClassLoader = new DexClassLoader(pluginStr,cache_plugin,null,
                mContext.getClassLoader());
        Class<?> superclass = dexClassLoader.getClass().getSuperclass();
        Field pathListField = superclass.getDeclaredField("pathList");
        pathListField.setAccessible(true);
        Object pathListObject = pathListField.get(dexClassLoader);
        Field dexElementsField = pathListObject.getClass().getDeclaredField("dexElements");
        dexElementsField.setAccessible(true);
        Object dexElementsObject = dexElementsField.get(pathListObject);
        //2：通过pathClassLoader获得宿主dexElements
        ClassLoader pathClassLoader =mContext.getClassLoader();
        Object hostPathListObject = pathListField.get(pathClassLoader);
        Object hostDexElementsObject = dexElementsField.get(hostPathListObject);
        //3：合并
        int pluginLength = Array.getLength(dexElementsObject);
        int hostLength = Array.getLength(hostDexElementsObject);
        int new_dexElementsLength = pluginLength + hostLength;
        Object newDexElements = Array.newInstance(hostDexElementsObject.getClass().getComponentType(),
                hostLength + pluginLength);
        for (int i = 0; i < new_dexElementsLength; i++) {
            if (i < pluginLength) {
                Array.set(newDexElements, i, Array.get(dexElementsObject, i));
            } else {
                Array.set(newDexElements, i, Array.get(hostDexElementsObject, i - pluginLength));
            }
        }
        //4.最后为类加载器通过反射将新的数组设置回pathClassLoader
        dexElementsField.set(hostPathListObject,newDexElements);
    }

    /**
     * 获取插件的Resources
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public Resources loadResources() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        AssetManager assetManager = AssetManager.class.newInstance();
        Method addAssetPathMethod = AssetManager.class.getMethod("addAssetPath", String.class);
        addAssetPathMethod.setAccessible(true);
        String pluginStr = mContext.getExternalFilesDir(null).getAbsolutePath()+"/pluginapp-debug.apk";
        addAssetPathMethod.invoke(assetManager, pluginStr);
        return new Resources(assetManager,mContext.getResources().getDisplayMetrics(),
                mContext.getResources().getConfiguration());

    }
}
